package com.syf.model;

import com.syf.enums.OrderDirection;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

/**
 * 【1】委托单的数据结构：
 *          每个 symbol交易对 对应一个 orderBooks
 */
@Data
@Slf4j
public class OrderBooks { //委托单账本： 所有的委托单总和
    /**
     * 所有的买入订单
     *      买入的限价交易 价格从高到底
     *      eg: 价格越高，越容易买到【还需要别人同意，是否买给你】
     *      Key: 价格
     *      MergeOrder 同价格的订单，订单按照时间排序
     */
    private TreeMap<BigDecimal, MergeOrder> buyLimitPrice;  //TreeMap: 会对传入的key进行了大小排序（红黑树）

    /**
     * 所有的卖出订单：
     *      自己卖出的限价交易，价格从低到高
     *      eg: 价格越低，卖出的越容易【别人都想低价买到】
     */
    private TreeMap<BigDecimal, MergeOrder> sellLimitPrice;
    /**
     * 交易的币种
     */
    private String symbol;

    /**
     * 交易币种的精度
     */
    private int coinScale;

    /**
     * 基币的精度
     */
    private int baseCoinScale;

    /**
     * 买方的盘口数据
     */
    private TradePlate buyTradePlate;

    /**
     * 卖方的盘口数据
     */
    private TradePlate sellTradePlate;

    /**
     * 日期格式器
     */
    private SimpleDateFormat dateTimeFormat;

    public OrderBooks(String symbol) {
        this(symbol, 4, 4);
    }

    public OrderBooks(String symbol, int coinScale, int baseCoinScale) {
        this.symbol = symbol;
        this.coinScale = coinScale;
        this.baseCoinScale = baseCoinScale;
        this.initialize();
    }


    /**
     * 初始化队列
     */
    public void initialize() {
        log.info("init CoinTrader for symbol {}", symbol);
        // 载入比较器
        buyLimitPrice = new TreeMap<>(Comparator.reverseOrder()); //价格从大到小【倒序】
        sellLimitPrice = new TreeMap<>(Comparator.naturalOrder()); // 价格从小到大【默认升序】

        buyTradePlate = new TradePlate(symbol, OrderDirection.BUY);
        sellTradePlate = new TradePlate(symbol, OrderDirection.SELL);
        dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }


    /**
     * 获取当前的交易的队列【卖出队列/买入队列】
     *
     * @return
     */
    public TreeMap<BigDecimal, MergeOrder> getCurrentLimitPrices(OrderDirection direction) {
        return direction == OrderDirection.BUY ? buyLimitPrice : sellLimitPrice;
    }


    /**
     * 获取当前的交易的队列迭代器
     *      entrySet实现了Set接口，里面存放的是键值对
     * @param direction
     * @return
     */
    public Iterator<Map.Entry<BigDecimal, MergeOrder>> getCurrentLimitPriceIterator(OrderDirection direction) {
        return getCurrentLimitPrices(direction).entrySet().iterator();
    }

   /* public static void main(String[] args) {
        TreeMap<Integer, String> map = new TreeMap<>();
        map.put(1,"打老虎");
        map.put(2,"老虎山");
        System.out.println("========:" + map.entrySet());  //[1=打老虎, 2=老虎山]
        for (Map.Entry<Integer, String> entry: map.entrySet()) {
            System.out.println(entry.getKey()+"--"+entry.getValue());
            //1--打老虎
            //2--老虎山
        }
    }*/

    /**
     * 怎么添加一个订单进入我们的 卖出/买入队列里面 【一轮价格 买单没买够】
     */
    public void addOrder(Order order) {
        //1.获取买入/卖出 队列
        TreeMap<BigDecimal, MergeOrder> currentLimitPrices = getCurrentLimitPrices(order.getOrderDirection());
        //2.根据价格 获取 指定的MergeOrder【hash碰撞，则链表连着；否则链表只存储一条记录】
        MergeOrder mergeOrder = currentLimitPrices.get(order.getPrice());  //挂单的价格 -》 所有的卖出/买入订单
        //
        if (mergeOrder == null) { // 之前在红黑树里面没有这个价格的key
            mergeOrder = new MergeOrder();
            currentLimitPrices.put(order.getPrice(), mergeOrder);  //将新的订单添加 队列中
        }
        //
        mergeOrder.add(order); //无论是否Hash碰撞，都添加进去

        // 将新的订单--添加到盘口中【只有购买后还没交易足够的委托单才会出现在盘口显示】
        if(order.getOrderDirection()==OrderDirection.BUY){
            buyTradePlate.add(order);   //【TradePlate盘口数据怎么来？】
        }else{
            sellTradePlate.add(order);
        }


    }

    /**
     * 取消一个委托订单(List中删除委托订单)
     */
    public void cancelOrder(Order order) {
        TreeMap<BigDecimal, MergeOrder> currentLimitPrices = getCurrentLimitPrices(order.getOrderDirection());
        MergeOrder mergeOrder = currentLimitPrices.get(order.getPrice());
        if (mergeOrder == null || mergeOrder.size() <= 0) {
            return;
        }
        Iterator<Order> iterator = mergeOrder.iterator();  //orders.iterator()
        while (iterator.hasNext()) {
            Order next = iterator.next();
            // 找到之前的我们的订单记录
            if (next.getOrderId().equals(order.getOrderId())) {
                iterator.remove();
            }
        }
        int size = mergeOrder.size(); // 删除之前,我们看合并订单的大小
        if (size == 0) { // 若我们的红黑树里面的合并订单的数据为空,我们摘除
            currentLimitPrices.remove(order.getPrice());
        }
        if(order.getOrderDirection()==OrderDirection.BUY){
            buyTradePlate.remove(order);
        }else{
            sellTradePlate.remove(order);
        }

    }


    /**
     * 获取排在队列里面的第一个数据
     */
    public Map.Entry<BigDecimal, MergeOrder> getBestSuitOrder(OrderDirection orderDirection) {
        return getCurrentLimitPrices(orderDirection).firstEntry();
    }

    public String getSymbol() {
        return symbol;
    }
}
